package com.gridmobi.xrtb.handler.impl;

import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.gridmobi.xrtb.common.ExecutorPool;
import com.gridmobi.xrtb.component.lucene.BidIndex;
import com.gridmobi.xrtb.component.lucene.SimpleBidData;
import com.gridmobi.xrtb.handler.InfoHandler;
import com.gridmobi.xrtb.handler.monitor.IpMonitor;
import com.gridmobi.xrtb.handler.monitor.RtbStatus;
import com.gridmobi.xrtb.handler.monitor.SimpleData;
import com.gridmobi.xrtb.routers.Info;
import org.apache.lucene.document.Document;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.Term;
import org.apache.lucene.search.*;
import org.apache.lucene.util.BytesRef;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@Component
public class InfoHandlerImpl implements InfoHandler {

    @Autowired
    IpMonitor ipMonitor;


    @Override
    public Object info() {
        if (!RtbStatus.INDEX_INIT_FINISHED.get()) {
            return "System is Setting";
        }

        Map lucene = Maps.newHashMap();
        BidIndex.INDEX_W_MAP.forEach((k, v) -> {
            JSONObject j = new JSONObject();
            j.put(Info.STATISTICS_ALL, v.numDocs());
            j.put(Info.STATISTICS_ACTIVE, v.maxDoc());
            j.put(Info.STATISTICS_RAM, v.numRamDocs());
            j.put(Info.STATISTICS_SEGMENTS, JSONObject.toJSONString(v.getMergingSegments()));
            lucene.put(k, j);

        });

        Map health = Maps.newHashMap();
        health.put("debuglog", RtbStatus.DEBUG_LOG.get());
        health.put("appstore", SimpleBidData.CAMPAIGN_APPSTOREURL);
        health.put("customer_impurl", SimpleBidData.LAND_URL_TRD);
        health.put("campaingsland", SimpleData.CAMPAIGNS_LANDURL);
        health.put("blocklist", SimpleBidData.GEO_OS_APP);
        health.put("microbids", SimpleBidData.MICRO_BID);
        health.put("GEOS", SimpleData.CAMPAIGNS_TARGET_COUNTRY);
        health.put("iplimits", ipMonitor.getIpcache().size());

        List list = Lists.newLinkedList();

        list.add("metrics(actuator/prometheus)");
        list.add("bidweight/{WEIGHT}");
        list.add("debuglog/999");
        list.add("georeqs");

        list.add("err-counter(" + RtbStatus.ERROR_TIMES.longValue() + ")");
        list.add("thread-pool-queuesize(" + ExecutorPool.getExecutor().getQueue().size() + ")");

        Map accumulator = Maps.newHashMap();


        list.add(accumulator);
        list.add(lucene);
        list.add(health);
        return list;
    }

    @Override
    public Object getDocs(IndexWriter writer, Integer count, String cid) {
        if (!RtbStatus.INDEX_INIT_FINISHED.get()) {
            return "System is Setting";
        }
        List<JSONObject> res = new ArrayList(count);
        try {
            IndexReader reader = DirectoryReader.open(writer);

            if (count != null && count > reader.maxDoc()) {
                count = reader.maxDoc();
            }
            for (int i = 0; i < count; i++) {
                res.add(BidIndex.doc2Json(reader.document(i)));
            }
            reader.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return res;
    }



    @Override
    public JSONObject getCampaign(String cid) {

        try {

            BooleanQuery.Builder builder = new BooleanQuery.Builder();
            builder.add(new TermQuery(new Term("id", cid)), BooleanClause.Occur.MUST);
            IndexSearcher searcher = null;
            IndexReader reader = DirectoryReader.open(BidIndex.CAMPAIGNS_W);
            searcher = new IndexSearcher(reader);
            Query query = new ConstantScoreQuery(builder.build()).getQuery();
            TopDocs results = searcher.search(query, 100);
            ScoreDoc[] hits = results.scoreDocs;
            for (ScoreDoc scoreDoc : hits) {
                Document doc = searcher.doc(scoreDoc.doc);
                return BidIndex.doc2Json(doc);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        return null;
    }

    @Override
    public Object getCampaing(String cid) {
        JSONObject info = new JSONObject();
        List<JSONObject> camapigns = Lists.newLinkedList();
        try {

            BooleanQuery.Builder builder = new BooleanQuery.Builder();
            builder.add(new TermQuery(new Term("id", cid)), BooleanClause.Occur.MUST);
            IndexSearcher searcher = null;
            IndexReader reader = DirectoryReader.open(BidIndex.CAMPAIGNS_W);
            searcher = new IndexSearcher(reader);
            Query query = new ConstantScoreQuery(builder.build()).getQuery();
            TopDocs results = searcher.search(query, 100);
            ScoreDoc[] hits = results.scoreDocs;
            for (ScoreDoc scoreDoc : hits) {
                Document doc = searcher.doc(scoreDoc.doc);
                camapigns.add(BidIndex.doc2Json(doc));
            }
            info.put("base", camapigns);
        } catch (Exception e) {
            e.printStackTrace();
        }
        if (!CollectionUtils.isEmpty(camapigns)) {

            String crids = camapigns.get(0).getString("CREATIVES");
            if (crids != null) {
                String[] cridarry = crids.split(",");
                try {
                    List<JSONObject> creatives = Lists.newLinkedList();
                    BooleanQuery.Builder builder = new BooleanQuery.Builder();
                    builder.add(new TermInSetQuery("id", Stream.of(cridarry).map(n -> new BytesRef(n)).collect(Collectors.toList())), BooleanClause.Occur.MUST);
                    IndexSearcher searcher = null;
                    IndexReader reader = DirectoryReader.open(BidIndex.CREATIVES_W);
                    searcher = new IndexSearcher(reader);
                    Query query = new ConstantScoreQuery(builder.build()).getQuery();
                    TopDocs results = searcher.search(query, 100);
                    ScoreDoc[] hits = results.scoreDocs;
                    for (ScoreDoc scoreDoc : hits) {
                        Document doc = searcher.doc(scoreDoc.doc);
                        creatives.add(BidIndex.doc2Json(doc));
                    }
                    info.put("creatives", creatives);
                } catch (Exception e) {
                    e.printStackTrace();
                }


                try {
                    List<JSONObject> natives = Lists.newLinkedList();
                    BooleanQuery.Builder builder = new BooleanQuery.Builder();
                    builder.add(new TermInSetQuery("id", Stream.of(cridarry).map(n -> new BytesRef(n)).collect(Collectors.toList())), BooleanClause.Occur.MUST);
                    IndexSearcher searcher = null;
                    IndexReader reader = DirectoryReader.open(BidIndex.CREATIVES_NATIVE_W);
                    searcher = new IndexSearcher(reader);
                    Query query = new ConstantScoreQuery(builder.build()).getQuery();
                    TopDocs results = searcher.search(query, 100);
                    ScoreDoc[] hits = results.scoreDocs;
                    for (ScoreDoc scoreDoc : hits) {
                        Document doc = searcher.doc(scoreDoc.doc);
                        natives.add(BidIndex.doc2Json(doc));
                    }
                    info.put("natives", natives);

                } catch (Exception e) {
                    e.printStackTrace();
                }

            }


            try {
                List<JSONObject> schedules = Lists.newLinkedList();
                BooleanQuery.Builder builder = new BooleanQuery.Builder();
                builder.add(new TermQuery(new Term("cid", cid)), BooleanClause.Occur.MUST);
                IndexSearcher searcher = null;
                IndexReader reader = DirectoryReader.open(BidIndex.CAMPAIGNS_SCHE_W);
                searcher = new IndexSearcher(reader);
                Query query = new ConstantScoreQuery(builder.build()).getQuery();
                TopDocs results = searcher.search(query, 100);
                ScoreDoc[] hits = results.scoreDocs;
                for (ScoreDoc scoreDoc : hits) {
                    Document doc = searcher.doc(scoreDoc.doc);
                    schedules.add(BidIndex.doc2Json(doc));
                }
                info.put("schedules", schedules);

            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return info;
    }
}
